﻿Imports System.Xml.Schema
Imports System.Xml
Imports Microsoft.Xna.Framework.Input

Public Class KeyMapCollection(Of DestType As {Structure, IConvertible}, SourceType As {Structure, IConvertible})
    Inherits Dictionary(Of DestType, SourceType)

    Public Sub New()
        ' Verify DestType and SourceType are Enums
        If Not GetType(DestType).IsEnum Or Not GetType(SourceType).IsEnum Then
            Throw New ArgumentException("DestType and SourceType must be an enumerated types")
        End If
    End Sub

    Private Shared Sub CheckType(Of T)(ByVal node As XmlNode, ByVal errorMessage As String)
        Dim aTypeName = node.InnerText
        Dim aType1 = Type.GetType(aTypeName)
        If aType1 <> GetType(T) Then
            Throw New IO.FileLoadException(String.Format(errorMessage, GetType(T).Name, aTypeName))
        End If
    End Sub

    Public Shared Function Load(ByRef xml As XmlDocument) As KeyMapCollection(Of DestType, SourceType)
        Dim node As XmlNode
        Dim fromName As String
        Dim fromAtt As XmlAttribute
        Dim fromValue As SourceType
        Dim toName As String
        Dim toAtt As XmlAttribute
        Dim toValue As DestType

        ' Verify DestType and SourceType are Enums
        If Not GetType(DestType).IsEnum Or Not GetType(SourceType).IsEnum Then
            Throw New ArgumentException("DestType and SourceType must be an enumerated types")
        End If

        ' Verify against schema
        xml.Schemas = InputHelpers.SchemaSet()
        xml.Validate(Sub() Throw New IO.FileLoadException("Invalid keymap XML"))

        ' Verify agains type names in xml
        CheckType(Of DestType)(xml.SelectSingleNode("/keymap/desttype"), "DestType %s not same as type %s defined in XML")
        CheckType(Of SourceType)(xml.SelectSingleNode("/keymap/sourcetype"), "SourceType %s not same as type %s defined in XML")

        ' Create KeyMap
        Load = New KeyMapCollection(Of DestType, SourceType)

        ' Load map items
        node = xml.SelectSingleNode("/keymap/map")
        Debug.Assert(node IsNot Nothing)

        For Each childNode As XmlNode In node.ChildNodes
            toAtt = childNode.Attributes("to")
            fromAtt = childNode.Attributes("from")

            toName = toAtt.InnerText
            fromName = fromAtt.InnerText

            If [Enum].TryParse(Of DestType)(toName, toValue) And [Enum].TryParse(Of SourceType)(fromName, fromValue) Then
                Load.Add(toValue, fromValue)
            End If
        Next

    End Function

End Class

